/**
 * @file modbus_task.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2025-01-08
 *
 * @copyright Copyright (c) 2025
 *
 */

/* includes ----------------------------------------------------------*/
#include "modbus_task.h"
#include "dal_log.h"
#include "dal_rng.h"
#include "mb_m.h"
#include "queue.h"
#include "semphr.h"

/* typedef -----------------------------------------------------------*/
static MotorCtrlPara_t uxMotorCtrlTask = {
    0,
    0,
    0,
    0,
};

static state_contrl_t uxStateCtrl = {
    DISABLE,
    eIdle,
};

static register_buffer_t RegBuffer;

/* define ------------------------------------------------------------*/
/* variables ---------------------------------------------------------*/

// Modbus主机轮训线程句柄
TaskHandle_t RtuMasterTask_Handler;
// Modbus主机轮训线程句柄
TaskHandle_t RtuSlaveTask_Handler;
// Modbus主机app线程句柄
TaskHandle_t RtuMasterAppTask_Handler;

QueueHandle_t app_semaphore = NULL;

/* function prototypes -----------------------------------------------*/

/**
 * @brief Modbus主机轮训线程
 *
 * @param pvParameters
 * @note
 *      2025-2-14：Modbus主机轮询线程优先级过低，则应该在最后一个线程
 *      加入vTaskDelay(100)等待该线程初始化完成
 */
void rtu_master_task(void* pvParameters)
{
    eMBMasterInit(MB_RTU, 0x2, 115200, MB_PAR_NONE);
    eMBMasterEnable();
    vMBMasterRunResRelease();
    log_d("rtu_master_task");
    while (1) {
        eMBMasterPoll();
        vTaskDelay(1);
    }
}

/**
 * @brief Modbus从机轮训线程
 *
 * @param pvParameters
 */
void rtu_slave_task(void* pvParameters)
{
    eMBInit(MB_RTU, 0x01, 0x1, 115200, MB_PAR_NONE);
    log_d("rtu_master_task");
    while (1) {
        eMBPoll();
        vTaskDelay(1);
    }
}

/**
 * @brief 设置电机是否要执行报警指令状态
 *
 * @param SdAlone
 */
static void prvbll_set_warn_state(uint8_t is_warn)
{
    uxStateCtrl.IsWarn = is_warn;
}

/**
 * @brief 获取电机报警指令状态
 *
 * @return uint8_t
 */
static uint8_t _u8bll_get_warn_status(void)
{
    return (uxStateCtrl.IsWarn);
}

/**
 * @brief 设置寄存器数量
 *
 * @param num
 */
static void vbll_set_register_number(uint8_t num)
{
    uxMotorCtrlTask.NRegs = num;
}

/**
 * @brief 设置任务状态机状态
 *
 * @param state
 */
static void prvbll_set_task_state(MotorState_t state)
{
    uxStateCtrl.state = state;
}

/**
 * @brief 释放写任务的消息队列
 *
 * @param ids
 * @param func
 * @param registers
 * @param NRegs
 * @note  用法：
 *        vbll_post_write(0x01, MB_FUNC_WRITE_MULTIPLE_REGISTERS,
 * 0x00E8,30000);
 */
void vbll_post_task(uint8_t ids, uint8_t func, uint16_t reg)
{
    uxMotorCtrlTask.request_id = ids;
    uxMotorCtrlTask.registers  = reg;
    uxMotorCtrlTask.functions  = func;
    if ((reg == mtReadWarnState) || (reg == mtSetAbsolutePosReg)) {
        prvbll_set_warn_state(ENABLE);
    }
    else {
        prvbll_set_warn_state(DISABLE);
    }
    xSemaphoreGive(app_semaphore);
}

/**
 * @brief 写指令写入寄存器缓冲区
 *
 * @param nRegs
 * @param register_data
 */
static void vbll_write_register_data(uint8_t nRegs, int32_t register_data)
{
    uxMotorCtrlTask.NRegs = nRegs;
    RegBuffer.ilWrite     = register_data;

    if (nRegs < 2) {
        RegBuffer.usModbusUserData[0] = (USHORT)(register_data);
    }
    else {
        RegBuffer.usModbusUserData[0] = (USHORT)(register_data & 0xFFFF);
        RegBuffer.usModbusUserData[1] = (USHORT)(register_data >> 16);
    }
}

/**
 * @brief 初始化寄存器缓存区
 *
 */
static void prvbll_RegBuffer_init(void)
{
    RegBuffer.ilWrite = 0;
    memset(RegBuffer.usModbusUserData, 0, sizeof(RegBuffer.usModbusUserData));
    memset(RegBuffer.ucModbusUserData, 0, sizeof(RegBuffer.ucModbusUserData));
}

/**
 * @brief 任务状态机写状态
 *
 */
static void prvbll_task_write(void)
{
    eMBMasterReqErrCode errorCodeWrite = MB_MRE_NO_ERR;

    // 写指令状态
    if (uxMotorCtrlTask.functions == MB_FUNC_WRITE_REGISTER) {
        // 写单个寄存器
        errorCodeWrite = eMBMasterReqWriteHolding(uxMotorCtrlTask.request_id,
                                                  uxMotorCtrlTask.registers,
                                                  RegBuffer.usModbusUserData[0],
                                                  100);
    }
    else if (uxMotorCtrlTask.functions == MB_FUNC_WRITE_MULTIPLE_REGISTERS) {
        // 写多个寄存器
        errorCodeWrite =
            eMBMasterReqWriteMultipleHolding(uxMotorCtrlTask.request_id,
                                             uxMotorCtrlTask.registers,
                                             uxMotorCtrlTask.NRegs,
                                             RegBuffer.usModbusUserData,
                                             100);
    }

    if (errorCodeWrite != MB_MRE_NO_ERR) {

        if ((_u8bll_get_warn_status() == ENABLE)) {

            log_d("write instruction 0x00E8 switch to warn state");

            // 每发一次电机移动指令，就去读取一次电机报警信息
            prvbll_set_task_state(eWarn);

            vbll_post_task(uxMotorCtrlTask.request_id,
                           MB_FUNC_READ_HOLDING_REGISTER,
                           uxMotorCtrlTask.registers);
        }
    }
    else {

        if (uxMotorCtrlTask.registers == mtSetAbsolutePosReg) {

            log_d("write instruction 0x00E8 switch to read state");

            // 使用0x00E8写指令状态成功，则切换到读状态指令
            prvbll_set_task_state(eRead);

            // 设置读寄存器数量
            vbll_set_register_number(1);

            // 电机运行状态及输入状态
            vbll_post_task(uxMotorCtrlTask.request_id,
                           MB_FUNC_READ_HOLDING_REGISTER,
                           mtControlStateReg);
        }
        else {
            // 其他写指令设置成功状态
            log_d("the write operation was successful");
        }
    }
}

/**
 * @brief 任务状态机读状态
 *
 * @param nRegs
 */
static void prvbll_task_read(void)
{
    eMBMasterReqErrCode errorCodeRead = MB_MRE_NO_ERR;

    uint32_t ulRegData = 0;

    uint16_t* pusRead = NULL;

    // 读取之前，先清空缓冲区地址
    memset(RegBuffer.usModbusUserData, 0, sizeof(RegBuffer.usModbusUserData));

    if (uxMotorCtrlTask.NRegs < 2) {
        pusRead = &RegBuffer.usModbusUserData[0];
    }
    else if (uxMotorCtrlTask.NRegs >= 2) {
        pusRead = RegBuffer.usModbusUserData;
    }

    if (uxMotorCtrlTask.functions == MB_FUNC_READ_HOLDING_REGISTER) {
        // 读单个寄存器的数据
        errorCodeRead = eMBMasterReqReadHolding(uxMotorCtrlTask.request_id,
                                                uxMotorCtrlTask.registers,
                                                uxMotorCtrlTask.NRegs,
                                                pusRead,
                                                100);
    }
    else if (uxMotorCtrlTask.functions == MB_FUNC_READ_INPUT_REGISTER) {
        // 读多个寄存器的数值
        errorCodeRead = eMBMasterReqReadInput(uxMotorCtrlTask.request_id,
                                              uxMotorCtrlTask.registers,
                                              uxMotorCtrlTask.NRegs,
                                              pusRead,
                                              100);
    }
    else {}

    ulRegData = RegBuffer.usModbusUserData[1] << 16;
    ulRegData |= (RegBuffer.usModbusUserData[0]);

    if (errorCodeRead != MB_MRE_NO_ERR) {
        // 释放信号量
        xSemaphoreGive(app_semaphore);
    }
    else {
        if (mtControlStateReg == uxMotorCtrlTask.registers) {
            if ((*pusRead >> 12)) {
                // 如果电机移动到指定的位置时，挂起任务
            }
            else {
                // 释放信号量
                xSemaphoreGive(app_semaphore);
            }
        }
        else {}
    }
}

/**
 * @brief Modbus主机app线程
 *
 * @param pvParameters
 */
void rtu_master_app_task(void* pvParameters)
{

    eMBMasterReqErrCode errorCode = MB_MRE_NO_ERR;

    // 初始化缓存寄存器缓存区
    prvbll_RegBuffer_init();

    // 创建二值信号量
    app_semaphore = xSemaphoreCreateBinary();

    log_d("rtu master app task");

    // 此处加入延时100时钟周期，等待Modbus线程初始化完成
    //    vTaskDelay(100);

    prvbll_set_task_state(eWrite);

    vbll_write_register_data(2, 1000);

    vbll_post_task(0x01, MB_FUNC_WRITE_MULTIPLE_REGISTERS, mtSetAbsolutePosReg);

    while (1) {

        if (app_semaphore != NULL) {

            if (xSemaphoreTake(app_semaphore, portMAX_DELAY) == pdTRUE) {
                switch (uxStateCtrl.state) {
                case eWrite: prvbll_task_write(); break;   // 写状态
                case eRead: prvbll_task_read(); break;     // 读状态
                case eWarn:
                    // 电机故障报警状态指令
                    errorCode =
                        eMBMasterReqReadHolding(uxMotorCtrlTask.request_id,
                                                mtReadWarnState,
                                                0x01,
                                                &RegBuffer.usModbusUserData[0],
                                                100);

                    if (uxMotorCtrlTask.registers == mtSetAbsolutePosReg) {

                        // 重新切换到写指令状态
                        prvbll_set_task_state(eWrite);

                        // 向寄存器写入数据
                        vbll_write_register_data(uxMotorCtrlTask.NRegs,
                                                 RegBuffer.ilWrite);

                        // 切换到写状态
                        vbll_post_task(uxMotorCtrlTask.request_id,
                                       MB_FUNC_WRITE_MULTIPLE_REGISTERS,
                                       mtSetAbsolutePosReg);
                    }
                    else {

                        if (errorCode != MB_MRE_NO_ERR) {

                            log_d("instruction send failed at 0x00A3");

                            xSemaphoreGive(app_semaphore);
                        }
                        else {
                            log_d("motor fault");
                        }
                    }
                    break;
                default: break;
                }
            }
        }
    }
}
